#region Copyright Notices
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
// 
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free
// Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#endregion

using System;
using System.IO;
using System.Collections;

namespace Yarr
{
	/// <summary>
	/// Definitions of built in Yarr setf methods
	/// </summary>
    [Package("system")]
	internal static partial class SetfMethods
	{
        private static string SYSTEM = "system";

        /// <summary>
        /// Setf method
        /// </summary>
        /// <param name="args"></param>
        /// <param name="environment"></param>
        /// <returns></returns>
        [Setf("aref", "(obj arr &rest index)")]
        public static Object Aref (Environment environment)
        {
            Object o = environment.GetValue(SYSTEM, "obj");
            Object arr = environment.GetValue(SYSTEM, "arr");
            Cons idx = (Cons)environment.GetValue(SYSTEM, "index");

            if (!(arr is Array))
            {
                if (arr is IList)
                    ((IList)arr)[(int)idx.First()] = o;

                else
                    throw new YarrException("Setf(aref): Second argument must be an array or IList");
            }
            else
            {
                int[] index = (int[])idx.ToArray();
                ((Array)arr).SetValue(o, index);
            }
            return o;
        }

        /// <summary>
        /// Setf method
        /// </summary>
        /// <param name="args"></param>
        /// <param name="environment"></param>
        /// <returns></returns>
        [Setf("elt", "(obj arr &rest index)")]
        public static Object Elt(Environment environment)
        {
            Object container = environment.GetValue(SYSTEM, "arr");

            if (!(container is IDictionary))
                return Aref(environment);

            object o = environment.GetValue(SYSTEM, "obj");
            ((IDictionary)container)[((Cons)environment.GetValue(SYSTEM, "index")).First()] = o;
            return o;
        }

        /// <summary>
        /// Setf method
        /// </summary>
        /// <param name="args"></param>
        /// <param name="environment"></param>
        /// <returns></returns>
        [Setf("get", "(obj (sym Yarr.Symbol) (prop Yarr.Symbol))")]
        public static Object Get(Environment environment)
        {
            return environment.SetProperty((Symbol)environment.GetValue(SYSTEM, "sym"),
                                           (Symbol)environment.GetValue(SYSTEM, "prop"),
                                           environment.GetValue(SYSTEM, "obj"));
        }


        /// <summary>
        /// Setf method
        /// </summary>
        /// <param name="args"></param>
        /// <param name="environment"></param>
        /// <returns></returns>
        [Setf("nth", "(val (index int32) cons)")]
        public static Object Nth (Environment environment)
        {
            object o = environment.GetValue(SYSTEM, "val");
            int index = (int)environment.GetValue(SYSTEM, "index");
            object cons = environment.GetValue(SYSTEM, "cons");

            if (cons is Cons)
                return ((Cons)cons).SetNth(index, o);

            if (cons is IList)
                return ((IList)cons)[index] = o;

            throw new YarrException("Setf(nth): Third argument must be a cons or IList");
        }

        /// <summary>
        /// Setf method
        /// </summary>
        /// <param name="args"></param>
        /// <param name="environment"></param>
        /// <returns></returns>
        [Setf("symbol-value", "(val (obj Yarr.Symbol))")]
        public static Object SymbolValue (Environment environment)
        {
            return environment[(Symbol)environment.GetValue(SYSTEM, "obj")] = environment.GetValue(SYSTEM, "val");
        }

        /// <summary>
        /// Setf method
        /// </summary>
        /// <param name="args"></param>
        /// <param name="environment"></param>
        /// <returns></returns>
        [Setf("car;first", "(val (lst Yarr.Cons))")]
        public static Object Car (Environment environment)
        {
            return ((Cons)environment.GetValue(SYSTEM, "lst")).SetCar(environment.GetValue(SYSTEM, "val"));
        }

        /// <summary>
        /// Setf method
        /// </summary>
        /// <param name="args"></param>
        /// <param name="environment"></param>
        /// <returns></returns>
        [Setf("call","(val prop inst &rest args)")]
        public static Object Call (Environment environment)
        {
            Object val = environment.GetValue(SYSTEM, "val");
            string prop = environment.GetValue(SYSTEM, "prop").ToString();
            Object inst = environment.GetValue(SYSTEM, "inst");
            Cons args = (Cons)environment.GetValue(SYSTEM, "args");

            return Runtime.SetDotNetValue(prop, inst, args, val, environment, false);
        }

        /// <summary>
        /// Setf method
        /// </summary>
        /// <param name="args"></param>
        /// <param name="environment"></param>
        /// <returns></returns>
        [Setf("cdr;rest", "(val (lst Yarr.Cons))")]
        public static Object Cdr (Environment environment)
        {
            return ((Cons)environment.GetValue(SYSTEM, "lst")).SetCdr(environment.GetValue(SYSTEM, "val"));
        }

        /// <summary>
        /// Setf method
        /// </summary>
        /// <param name="args"></param>
        /// <param name="environment"></param>
        /// <returns></returns>
        [Setf("caar", "(val (lst Yarr.Cons))")]
        public static Object Caar (Environment environment)
        {
            return ((Cons)environment.GetValue(SYSTEM, "lst")).SetCaar(environment.GetValue(SYSTEM, "val"));
        }

        /// <summary>
        /// Setf method
        /// </summary>
        /// <param name="args"></param>
        /// <param name="environment"></param>
        /// <returns></returns>
        [Setf("cadr;second", "(val (lst Yarr.Cons))")]
        public static Object Cadr (Environment environment)
        {
            return ((Cons)environment.GetValue(SYSTEM, "lst")).SetCadr(environment.GetValue(SYSTEM, "val"));
        }

        /// <summary>
        /// Setf method
        /// </summary>
        /// <param name="args"></param>
        /// <param name="environment"></param>
        /// <returns></returns>
        [Setf("cdar", "(val (lst Yarr.Cons))")]
        public static Object Cdar (Environment environment)
        {
            return ((Cons)environment.GetValue(SYSTEM, "lst")).SetCdar(environment.GetValue(SYSTEM, "val"));
        }

        /// <summary>
        /// Setf method
        /// </summary>
        /// <param name="args"></param>
        /// <param name="environment"></param>
        /// <returns></returns>
        [Setf("cddr", "(val (lst Yarr.Cons))")]
        public static Object Cddr (Environment environment)
        {
            return ((Cons)environment.GetValue(SYSTEM, "lst")).SetCddr(environment.GetValue(SYSTEM, "val"));
        }

        /// <summary>
        /// Setf method
        /// </summary>
        /// <param name="args"></param>
        /// <param name="environment"></param>
        /// <returns></returns>
        [Setf("caaar", "(val (lst Yarr.Cons))")]
        public static Object Caaar (Environment environment)
        {
            return ((Cons)environment.GetValue(SYSTEM, "lst")).SetCaaar(environment.GetValue(SYSTEM, "val"));
        }

        /// <summary>
        /// Setf method
        /// </summary>
        /// <param name="args"></param>
        /// <param name="environment"></param>
        /// <returns></returns>
        [Setf("caadr", "(val (lst Yarr.Cons))")]
        public static Object Caadr (Environment environment)
        {
            return ((Cons)environment.GetValue(SYSTEM, "lst")).SetCaadr(environment.GetValue(SYSTEM, "val"));
        }

        /// <summary>
        /// Setf method
        /// </summary>
        /// <param name="args"></param>
        /// <param name="environment"></param>
        /// <returns></returns>
        [Setf("cadar", "(val (lst Yarr.Cons))")]
        public static Object Cadar (Environment environment)
        {
            return ((Cons)environment.GetValue(SYSTEM, "lst")).SetCadar(environment.GetValue(SYSTEM, "val"));
        }

        /// <summary>
        /// Setf method
        /// </summary>
        /// <param name="args"></param>
        /// <param name="environment"></param>
        /// <returns></returns>
        [Setf("caddr;third", "(val (lst Yarr.Cons))")]
        public static Object Caddr (Environment environment)
        {
            return ((Cons)environment.GetValue(SYSTEM, "lst")).SetCaddr(environment.GetValue(SYSTEM, "val"));
        }

        /// <summary>
        /// Setf method
        /// </summary>
        /// <param name="args"></param>
        /// <param name="environment"></param>
        /// <returns></returns>
        [Setf("cdaar", "(val (lst Yarr.Cons))")]
        public static Object Cdaar (Environment environment)
        {
            return ((Cons)environment.GetValue(SYSTEM, "lst")).SetCdaar(environment.GetValue(SYSTEM, "val"));
        }

        /// <summary>
        /// Setf method
        /// </summary>
        /// <param name="args"></param>
        /// <param name="environment"></param>
        /// <returns></returns>
        [Setf("cdadr", "(val (lst Yarr.Cons))")]
        public static Object Cdadr (Environment environment)
        {
            return ((Cons)environment.GetValue(SYSTEM, "lst")).SetCdadr(environment.GetValue(SYSTEM, "val"));
        }

        /// <summary>
        /// Setf method
        /// </summary>
        /// <param name="args"></param>
        /// <param name="environment"></param>
        /// <returns></returns>
        [Setf("Cddar", "(val (lst Yarr.Cons))")]
        public static Object Cddar (Environment environment)
        {
            return ((Cons)environment.GetValue(SYSTEM, "lst")).SetCddar(environment.GetValue(SYSTEM, "val"));
        }

        /// <summary>
        /// Setf method
        /// </summary>
        /// <param name="args"></param>
        /// <param name="environment"></param>
        /// <returns></returns>
        [Setf("cdddr", "(val (lst Yarr.Cons))")]
        public static Object Cdddr (Environment environment)
        {
            return ((Cons)environment.GetValue(SYSTEM, "lst")).SetCdddr(environment.GetValue(SYSTEM, "val"));
        }
	}
}
